using System.Collections.Generic;
using System.Text;
using Magiq.Support;

namespace Magiq.Databases
{
    public class SelectStatementParser
    {
        private const string GroupOpenStuff = "([\"";
        private const string GroupCloseStuff = ")]\"";
        private const char Delimiter = ',';
        private const string FromDelimiter = " from ";
        private static readonly IList<char> Operations = "+-*%/".ToCharArray();

        private static string Normalize(string statement)
        {
            return statement.ToLowerInvariant().Replace("\r\n", " ").GetFrom("select").Trim();
        }

        public SelectStatementInformation Parse(string statement)
        {
            var currentValue = new StringBuilder();
            var expectedStuffToClose = new Stack<char>();
            string valueToReturn = null;
            var normalized = Normalize(statement);
            var from = string.Empty;
            var values = new List<string>();

            var emptyValue = true;
            var operationOpened = false;
            char? previous = null;

            for (var i = 0; i < normalized.Length && string.IsNullOrEmpty(from); i++)
            {
                var c = normalized[i];

                if (expectedStuffToClose.Count == 0)
                {
                    if (emptyValue)
                    {
                        if (c != ' ')
                            emptyValue = false;
                        else
                            continue;
                    }

                    if (Operations.Contains(c))
                    {
                        operationOpened = true;
                    }
                    else if (valueToReturn == null && i > 0 && previous.HasValue && previous.Value == ' ' &&
                             !Operations.Contains(c) && c != ' ' & c != ',')
                    {
                        if (operationOpened)
                            operationOpened = false;
                        else
                            valueToReturn = currentValue.ToString();
                    }
                    else if (normalized.Length - i > FromDelimiter.Length &&
                             normalized.Substring(i, FromDelimiter.Length) == FromDelimiter)
                    {
                        valueToReturn = currentValue.ToString();
                        from = normalized.Substring(i + FromDelimiter.Length).Trim();
                        break;
                    }
                    else if (c == Delimiter)
                    {
                        if (valueToReturn == null)
                            valueToReturn = currentValue.ToString();
                        values.Add(valueToReturn.Trim());
                        valueToReturn = null;
                        currentValue = new StringBuilder();
                        operationOpened = false;
                        emptyValue = true;
                        previous = c;
                        continue;
                    }
                }
                if (!emptyValue)
                    previous = c;

                if (valueToReturn != null) continue;

                currentValue.Append(c);

                if (expectedStuffToClose.Count > 0 && expectedStuffToClose.Peek() == c)
                {
                    expectedStuffToClose.Pop();
                }
                else
                {
                    var indexOfCInOpenStuff = GroupOpenStuff.IndexOf(c);
                    if (indexOfCInOpenStuff > -1)
                        expectedStuffToClose.Push(GroupCloseStuff[indexOfCInOpenStuff]);
                }
            }
            if (valueToReturn == null)
                valueToReturn = currentValue.ToString();

            values.Add(valueToReturn.Trim());

            return new SelectStatementInformation(from, values);
        }
    }
}